package easyjava.function;

import static easyjava.function.CastFunction.castToObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Map;

/**
 * 对象遍历相关方法
 *
 */
public interface EachFunction {
	
	@FunctionalInterface
    interface EachFun<T> {
        void handle(T item);
    }
	
	@FunctionalInterface
	interface EachMapFun<K,V>{
		void handle(K key,V value);
	}

	class AfterEachFun{
		
		private boolean isUnSupported;
		private boolean isEmpty;
		
		public AfterEachFun(boolean unsupported,boolean empty) {
			this.isUnSupported = unsupported;
			this.isEmpty = empty;
		}
		
		AfterEachFun unsupported(Runnable action) {
			if(isUnSupported) action.run();
			return this;
		}
		
		AfterEachFun empty(Runnable action) {
			if(isEmpty) action.run();
			return this;
		}
		
		void last(Runnable action) {
			action.run();
		}
	}
	
	static <T> AfterEachFun each(Object obj,EachFun<T> eachFun) {
		if(obj == null) return new AfterEachFun(true, true);
		
		if(obj.getClass().isArray()) {
			Object[] arrObj = castToObject(obj);
			for(Object item:arrObj) {
				eachFun.handle((T) item);
			}
		}else if(obj instanceof String) {
			for(int i=0,len=((String) obj).length();i<len;i++) {
				Character c = ((String) obj).charAt(i);
				eachFun.handle((T) c);
			}
		}else if(obj instanceof Iterable) {
			for(Object item:(Iterable)obj) {
				eachFun.handle((T) item);
			}
		}else if(obj instanceof File && ((File) obj).isDirectory()) {
			File[] subFiles=((File) obj).listFiles();
			for(File subFile:subFiles) {
				eachFun.handle((T) subFile);
			}
		}else if(obj instanceof File && ((File) obj).isFile()) {
			try(BufferedReader reader=new BufferedReader(new FileReader((File)obj))){
				String tempStr = null;
				while((tempStr=reader.readLine())!=null) {
					eachFun.handle((T)tempStr);
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}else{
			return new AfterEachFun(true, false);
		}
		return new AfterEachFun(false, false);
	}
	
	static <K,V> AfterEachFun each(Object obj,EachMapFun<K,V> eachFun) {
		if(obj==null) return new AfterEachFun(true, true);
		
		if(obj instanceof Map) {
			for(Map.Entry<K,V> entry:((Map<K,V>) obj).entrySet()) {
				eachFun.handle(entry.getKey(), entry.getValue());
			}
		}else{
			return new AfterEachFun(true, false);
		}
		return new AfterEachFun(false, false);
	}
}
